﻿/*************************************************
二进制流读写类
author：Daixiwei
**************************************************/
using Decompression.Zlib;
using System;
using System.IO;
using System.Text;

namespace taurus.client
{
    public class ByteArray
    {
        private byte[] buffer;
        private int _position;

        public ByteArray()
        {
            _position = 0;
            buffer = new byte[0];
        }

        public ByteArray(byte[] buf)
        {
            _position = 0;
            buffer = buf;
        }


        public bool readBool()
        {
            return (buffer[_position++] == 1);
        }

        public byte readByte()
        {
            return buffer[_position++];
        }

        public byte[] readBytes(int count)
        {
            byte[] dst = new byte[count];
            Buffer.BlockCopy(buffer, _position, dst, 0, count);
            _position += count;
            return dst;
        }

        public double readDouble()
        {
            return BitConverter.ToDouble(reverseOrder(readBytes(8)), 0);
        }

        public float readFloat()
        {
            return BitConverter.ToSingle(reverseOrder(readBytes(4)), 0);
        }

        public int readInt()
        {
            return BitConverter.ToInt32(reverseOrder(readBytes(4)), 0);
        }

        public long readLong()
        {
            return BitConverter.ToInt64(reverseOrder(readBytes(8)), 0);
        }

        public short readShort()
        {
            return BitConverter.ToInt16(reverseOrder(readBytes(2)), 0);
        }

        public ushort readUShort()
        {
            return BitConverter.ToUInt16(reverseOrder(readBytes(2)), 0);
        }

        public string readString()
        {
            int count = readUShort();
            if (count == 0) return string.Empty;
            string str = Encoding.UTF8.GetString(buffer, _position, count);
            _position += count;
            return str;
        }

        private byte[] reverseOrder(byte[] dt)
        {
            if (!BitConverter.IsLittleEndian)
            {
                return dt;
            }
            byte[] buffer = new byte[dt.Length];
            int num = 0;
            for (int i = dt.Length - 1; i >= 0; i--)
            {
                buffer[num++] = dt[i];
            }
            return buffer;
        }

        public void writeBool(bool b)
        {
            byte[] data = new byte[] { !b ? ((byte)0) : ((byte)1) };
            writeBytes(data);
        }

        public void writeByte(byte b)
        {
            byte[] data = new byte[] { b };
            writeBytes(data);
        }

        public void writeBytes(byte[] data)
        {
            writeBytes(data, 0, data.Length);
        }

        public void writeBytes(byte[] data, int ofs, int count)
        {
            byte[] dst = new byte[count + buffer.Length];
            Buffer.BlockCopy(buffer, 0, dst, 0, buffer.Length);
            Buffer.BlockCopy(data, ofs, dst, buffer.Length, count);
            buffer = dst;
        }

        public void writeDouble(double d)
        {
            byte[] bytes = BitConverter.GetBytes(d);
            writeBytes(reverseOrder(bytes));
        }

        public void writeFloat(float f)
        {
            byte[] bytes = BitConverter.GetBytes(f);
            writeBytes(reverseOrder(bytes));
        }

        public void writeInt(int i)
        {
            byte[] bytes = BitConverter.GetBytes(i);
            writeBytes(reverseOrder(bytes));
        }

        public void writeLong(long l)
        {
            byte[] bytes = BitConverter.GetBytes(l);
            writeBytes(reverseOrder(bytes));
        }

        public void writeShort(short s)
        {
            byte[] bytes = BitConverter.GetBytes(s);
            writeBytes(reverseOrder(bytes));
        }

        public void writeUShort(ushort us)
        {
            byte[] bytes = BitConverter.GetBytes(us);
            writeBytes(reverseOrder(bytes));
        }

        public void writeString(string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                writeUShort(0);
                return;
            }
            var bytes = Encoding.UTF8.GetBytes(str);
            int num = bytes.Length;
            writeUShort(Convert.ToUInt16(num));
            writeBytes(bytes);
        }

        /// <summary>
        /// zlib解压缩
        /// </summary>
        public void uncompress(){
            using (var input = new System.IO.MemoryStream(buffer))
            {
                Stream decompressor = new ZlibBaseStream(input, CompressionMode.Decompress, CompressionLevel.BestCompression, ZlibStreamFlavor.ZLIB, true);
                this.buffer = ZlibBaseStream.UncompressBuffer(buffer, decompressor);
            }
            this._position = 0;
        }

        /// <summary>
        /// zlib压缩
        /// </summary>
        public void compress(){
            using (var ms = new System.IO.MemoryStream())
            {
                Stream compressor = new ZlibBaseStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression, ZlibStreamFlavor.ZLIB, true);
                ZlibBaseStream.CompressBuffer(buffer, compressor);
                buffer = ms.ToArray();
            }
            this._position = 0;
        }

        public byte[] bytes
        {
            get
            {
                return buffer;
            }
            set
            {
                buffer = value;
            }
        }

        public int bytesAvailable
        {
            get
            {
                int num = buffer.Length - _position;
                if ((num <= buffer.Length) && (num >= 0))
                {
                    return num;
                }
                return 0;
            }
        }

        /// <summary>
        /// get length
        /// </summary>
        public int length
        {
            get{
                return buffer.Length;
            }
        }

        /// <summary>
        ///  position.
        /// </summary>
        public int position
        {
            get { return this._position; }
            set { this._position = value; }
        }

        
    }
}